////////////////////////////////////////////////////////////////////////
//
//     Copyright (c) 2009-2013 Denim Group, Ltd.
//
//     The contents of this file are subject to the Mozilla Public License
//     Version 2.0 (the "License"); you may not use this file except in
//     compliance with the License. You may obtain a copy of the License at
//     http://www.mozilla.org/MPL/
//
//     Software distributed under the License is distributed on an "AS IS"
//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//     License for the specific language governing rights and limitations
//     under the License.
//
//     The Original Code is ThreadFix.
//
//     The Initial Developer of the Original Code is Denim Group, Ltd.
//     Portions created by Denim Group, Ltd. are Copyright (C)
//     Denim Group, Ltd. All Rights Reserved.
//
//     Contributor(s): Denim Group, Ltd.
//
////////////////////////////////////////////////////////////////////////
package com.denimgroup.threadfix.data.dao.hibernate;

import java.util.List;

import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.denimgroup.threadfix.data.dao.ChannelVulnerabilityDao;
import com.denimgroup.threadfix.data.entities.ChannelType;
import com.denimgroup.threadfix.data.entities.ChannelVulnerability;

@Repository
@Transactional
public class HibernateChannelVulnerabilityDao implements
		ChannelVulnerabilityDao {

	private SessionFactory sessionFactory;

	@Autowired
	public HibernateChannelVulnerabilityDao(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	@Override
	public ChannelVulnerability retrieveByCode(ChannelType channelType,
			String code) {

		return (ChannelVulnerability) sessionFactory.getCurrentSession()
							 .createCriteria(ChannelVulnerability.class)
							 .add( Restrictions.eq("code", code).ignoreCase() )
							 .add( Restrictions.eq("channelType", channelType) )
							 .uniqueResult();
				
	}
	

	@Override
	public ChannelVulnerability retrieveByName(ChannelType channelType,
			String name) {
		@SuppressWarnings("unchecked")
		List<ChannelVulnerability> vulns = sessionFactory.getCurrentSession()
				 .createCriteria(ChannelVulnerability.class)
				 .add( Restrictions.eq("name", name).ignoreCase() )
				 .add( Restrictions.eq("channelType", channelType) )
				 .list();
		
		if (vulns == null || vulns.isEmpty()) {
			return null;
		} else {
			return vulns.get(0);
		}
	}

	@Override
	public ChannelVulnerability retrieveById(int id) {
		return (ChannelVulnerability) sessionFactory.getCurrentSession().get(
				ChannelVulnerability.class, id);
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<ChannelVulnerability> retrieveSuggested(String prefix) {
		Integer manualId = (Integer) sessionFactory.getCurrentSession()
				.createQuery("select id from ChannelType where name='Manual'")
				.uniqueResult();
		return sessionFactory
				.getCurrentSession()
				.createQuery(
						"from ChannelVulnerability cv where cv.code like "
								+ ":prefix and cv.channelType = :channelTypeId")
				.setString("prefix","%" + prefix + "%")
				.setInteger("channelTypeId", manualId).list();
	}

	@Override
	public void saveOrUpdate(ChannelVulnerability channelVulnerability) {
		sessionFactory.getCurrentSession().saveOrUpdate(channelVulnerability);
	}
	
	@Override
	public boolean isValidManualName(String name) {
		Integer manualId = (Integer) sessionFactory.getCurrentSession()
				.createQuery("select id from ChannelType where name='Manual'")
				.uniqueResult();
		List<?> channelVulns = sessionFactory
				.getCurrentSession()
				.createQuery("from ChannelVulnerability cv where cv.code = "
								+ ":prefix and cv.channelType = :channelTypeId")
				.setString("prefix", name)
				.setInteger("channelTypeId", manualId).list();
		
		return channelVulns != null && channelVulns.size() == 1;
	}

	@Override
	public boolean hasMappings(int id) {
		 Object result = sessionFactory.getCurrentSession().createQuery(
				 	"from VulnerabilityMap map where map.channelVulnerability = :channelVuln")
		 		.setInteger("channelVuln", id).list();
		 
		 return result == null;
	}
}
